﻿using System;
using System.Collections.Generic;
using GeoAPI.CoordinateSystems.Transformations;
using GeoAPI.Geometries;

namespace NetTopologySuite.CoordinateSystems.Transformations
{
	public class GeometryTransform
	{
		private static double[] ToArray(double x, double y)
		{
			return new double[]
			{
				x,
				y
			};
		}

		public static Envelope TransformBox(Envelope box, IMathTransform transform)
		{
            if (box == null)
            {
                return null;
            }
            double[][] array = new double[][]
			{
				transform.Transform(GeometryTransform.ToArray(box.MinX, box.MinY)),
				transform.Transform(GeometryTransform.ToArray(box.MaxX, box.MaxY)),
				transform.Transform(GeometryTransform.ToArray(box.MinX, box.MaxY)),
				transform.Transform(GeometryTransform.ToArray(box.MaxX, box.MinY))
			};
            Envelope envelope = new Envelope();
            foreach (double[] array3 in array)
            {
                envelope.ExpandToInclude(array3[0], array3[1]);
            }
            return envelope;
		}

		public static IGeometry TransformGeometry(IGeometryFactory factory, IGeometry g, IMathTransform transform)
		{
			if (g == null)
			{
				return null;
			}
			if (g is IPoint)
			{
				return GeometryTransform.TransformPoint(factory, g as IPoint, transform);
			}
			if (g is ILineString)
			{
				return GeometryTransform.TransformLineString(factory, g as ILineString, transform);
			}
			if (g is IPolygon)
			{
				return GeometryTransform.TransformPolygon(factory, g as IPolygon, transform);
			}
			if (g is IMultiPoint)
			{
				return GeometryTransform.TransformMultiPoint(factory, g as IMultiPoint, transform);
			}
			if (g is IMultiLineString)
			{
				return GeometryTransform.TransformMultiLineString(factory, g as IMultiLineString, transform);
			}
			if (g is IMultiPolygon)
			{
				return GeometryTransform.TransformMultiPolygon(factory, g as IMultiPolygon, transform);
			}
			if (g is IGeometryCollection)
			{
				return GeometryTransform.TransformGeometryCollection(factory, g as IGeometryCollection, transform);
			}
			throw new ArgumentException(string.Format("Could not transform geometry type '{0}'", g.GetType()));
		}

		public static IPoint TransformPoint(IGeometryFactory factory, IPoint p, IMathTransform transform)
		{
			IPoint result;
			try
			{
				ICoordinateSequence coordinates = transform.Transform(p.CoordinateSequence);
				result = factory.CreatePoint(coordinates);
			}
			catch
			{
				result = null;
			}
			return result;
		}

		public static ILineString TransformLineString(IGeometryFactory factory, ILineString l, IMathTransform transform)
		{
			ILineString result;
			try
			{
				ICoordinateSequence coordinates = transform.Transform(l.CoordinateSequence);
				result = factory.CreateLineString(coordinates);
			}
			catch
			{
				result = null;
			}
			return result;
		}

		public static ILinearRing TransformLinearRing(IGeometryFactory factory, ILinearRing r, IMathTransform transform)
		{
			ILinearRing result;
			try
			{
				ICoordinateSequence coordinates = transform.Transform(r.CoordinateSequence);
				result = factory.CreateLinearRing(coordinates);
			}
			catch
			{
				result = null;
			}
			return result;
		}

		public static IPolygon TransformPolygon(IGeometryFactory factory, IPolygon p, IMathTransform transform)
		{
			List<ILinearRing> list = new List<ILinearRing>(p.InteriorRings.Length);
			for (int i = 0; i < p.InteriorRings.Length; i++)
			{
				ILinearRing item = GeometryTransform.TransformLinearRing(factory, (ILinearRing)p.InteriorRings[i], transform);
				list.Add(item);
			}
			ILinearRing shell = GeometryTransform.TransformLinearRing(factory, (ILinearRing)p.ExteriorRing, transform);
			return factory.CreatePolygon(shell, list.ToArray());
		}

		public static IMultiPoint TransformMultiPoint(IGeometryFactory factory, IMultiPoint points, IMathTransform transform)
		{
			Ordinates ordinates = ((IPoint)points.GetGeometryN(0)).CoordinateSequence.Ordinates;
			Ordinate[] array = OrdinatesUtility.ToOrdinateArray(ordinates, 4);
			ICoordinateSequence coordinateSequence = factory.CoordinateSequenceFactory.Create(points.NumPoints, ordinates);
			for (int i = 0; i < points.NumGeometries; i++)
			{
				ICoordinateSequence coordinateSequence2 = ((IPoint)points.GetGeometryN(i)).CoordinateSequence;
				foreach (Ordinate ordinate in array)
				{
					double ordinate2 = coordinateSequence2.GetOrdinate(0, ordinate);
					coordinateSequence.SetOrdinate(i, ordinate, ordinate2);
				}
			}
			ICoordinateSequence coordinates = transform.Transform(coordinateSequence);
			return factory.CreateMultiPoint(coordinates);
		}

		public static IMultiLineString TransformMultiLineString(IGeometryFactory factory, IMultiLineString lines, IMathTransform transform)
		{
			List<ILineString> list = new List<ILineString>(lines.Geometries.Length);
			foreach (IGeometry geometry in lines.Geometries)
			{
				ILineString item = GeometryTransform.TransformLineString(factory, (ILineString)geometry, transform);
				list.Add(item);
			}
			return factory.CreateMultiLineString(list.ToArray());
		}

		public static IMultiPolygon TransformMultiPolygon(IGeometryFactory factory, IMultiPolygon polys, IMathTransform transform)
		{
			IGeometry[] geometries = polys.Geometries;
			List<IPolygon> list = new List<IPolygon>(geometries.Length);
			foreach (IGeometry geometry in geometries)
			{
				IPolygon item = GeometryTransform.TransformPolygon(factory, (IPolygon)geometry, transform);
				list.Add(item);
			}
			return factory.CreateMultiPolygon(list.ToArray());
		}

		public static IGeometryCollection TransformGeometryCollection(IGeometryFactory factory, IGeometryCollection geoms, IMathTransform transform)
		{
			IGeometry[] geometries = geoms.Geometries;
			List<IGeometry> list = new List<IGeometry>(geometries.Length);
			foreach (IGeometry g in geometries)
			{
				IGeometry item = GeometryTransform.TransformGeometry(factory, g, transform);
				list.Add(item);
			}
			return factory.CreateGeometryCollection(list.ToArray());
		}
	}
}
